﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Reflection;
using NHibernate;

namespace NMA.Infrastructure.NHibernate.Repository
{
    using NMA.Domain.Model;
    using NMA.Domain.Model.Repository;
    using NMA.Infrastructure.Logging;
    using NMA.Infrastructure.NHibernate.Container;
    using NMA.Infrastructure.NHibernate.UnitOfWork;
    using NMA.Infrastructure.DBC;
    using NMA.Infrastructure.NHibernate.DomainObject;
    using NMA.Domain.Shared.Paging;

    public class ResourceRepository : BaseRepository<IResources>, IResourceRepository
    {
        #region variables

        protected IUnitOfWorkFactory UnitOfWorkFactory { get; private set; }

        private static readonly ILog _logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        #endregion

        #region contructors

        public ResourceRepository() : this(IoC.GetInstance<IUnitOfWorkFactory>())
        { }

        internal ResourceRepository(IUnitOfWorkFactory unitOfWorkFactory) 
        {
            UnitOfWorkFactory = unitOfWorkFactory;
        }

        #endregion

        #region implement functions

        public IEnumerable<IResources> All()
        {
            using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
            {
                ICriteria critreria = uow.Session.CreateCriteria<Resources>();
                uow.Commit();
                return critreria.List<Resources>();
            }
        }

        public IResources GetById(Guid id)
        {
            Check.Assert(id != null, "Id is null");

            try
            {
                IResources resources;

                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    resources = uow.Session.Get<Resources>(id);
                    uow.Commit();
                }

                return resources;
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            } 
        }

        public Guid Add(IResources entity)
        {
            Check.Assert(entity != null, "Resources's instance is null");

            try
            {
                object result = null;

                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    result = uow.Session.Save(entity);

                    uow.Session.Flush();
                    uow.Session.Clear();

                    uow.Commit();
                }

                return (Guid)result;
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            }
        }

        public void Remove(IResources entity)
        {
            Check.Assert(entity != null, "Resources's object is null");

            try
            {
                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    uow.Session.Delete(entity);
                    uow.Commit();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            }
        }

        public void Remove(Guid id)
        {
            Check.Assert(id != null, "Resources's id is null");

            try
            {
                var entity = GetById(id);

                if (entity == null)
                    throw new Exception("Resources's entity is null");

                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    uow.Session.Delete(entity);
                    uow.Commit();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            }
        }

        public void Update(IResources entity)
        {
            Check.Assert(entity != null, "Resources's entity is null");

            try
            {
                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    uow.Session.Update(entity);
                    uow.Commit();
                }
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            } 
        }

        public IEnumerable<IResources> GetBy(Expression<Func<IResources, bool>> condition)
        {
            Check.Assert(condition != null, "Condition for searching resources is null");

            try
            {
                IEnumerable<IResources> result = null;
                IList<IResources> listOfResources = null;

                using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
                {
                    // creating criteria for this condition
                    ICriteria criteria = uow.Session.CreateCriteria(typeof(IResources));
                    // getting result from criteria
                    listOfResources = criteria.List<IResources>();

                    if (listOfResources == null)
                        throw new Exception("List of audit is null");

                    result = listOfResources.Where<IResources>(condition.Compile());
                }

                return result;
            }
            catch (Exception ex)
            {
                _logger.Error(ex.Message);
                throw ex;
            } 
        }

        public IPagedList<IResources> All(int pageIndex, int pageSize)
        {
            using (var uow = UnitOfWorkFactory.GetNewUnitOfWork())
            {
                var criteria = uow.Session.CreateCriteria(typeof(Resources));

                return PagedList(criteria, pageIndex, pageSize);
            }
        }
    
        #endregion
    }
}